/*
  Name: MiniClientCanvas.cpp
  Copyright:
  Author: Carl Chatfield
  Date: 23/01/08 19:56
  Description: GL canvas for drawing mini client to
*/

//#include <gl/glu.h>
#include <stdio.h>
#include <math.h>

#include	<gl\gl.h>							// Header File For The OpenGL32 Library
#include	<gl\glu.h>							// Header File For The GLu32 Library
#include    <gl\glext.h>
#include    "windows.h"
#include	<gl\glaux.cpp>	

#include "MiniClientCanvas.h"
#include "DeadProxyDatReader.h"
#include "DeadProxyApp.h"



int map[30] = {429, 429, 429, 429, 429, 429, 429, 429, 429, 429, 429, 429,4398,4518,4522,
                429, 429, 429, 429, 429, 429, 429, 429, 429, 429, 414, 429,4394,4403,4525};
                

// Event Table
BEGIN_EVENT_TABLE(MiniClientCanvas, wxGLCanvas)
	EVT_PAINT(MiniClientCanvas::OnPaint)
	EVT_ERASE_BACKGROUND(MiniClientCanvas::OnEraseBackground)
	EVT_IDLE(MiniClientCanvas::OnIdle)
    EVT_UPDATE_MINICLIENT(wxUPDATE_MINICLIENT_ID, MiniClientCanvas::OnDraw)
END_EVENT_TABLE()




MiniClientCanvas::MiniClientCanvas(wxWindow* parent,
                                wxWindowID id,
                                int* attribList,                                
                                const wxPoint& pos,
                                const wxSize& size,
                                long style,
                                const wxString& name,
                                const wxPalette& palette)
: wxGLCanvas(parent, id, attribList, pos, size, style, name, palette)
{
    RCContext = new wxGLContext(this);
    width = size.GetWidth();
    height = size.GetHeight();
    
    texture = new Text[23260];
    memset(texture, 0, sizeof(Text)*23260);
    
    Log1 = new TextLog;
    Log1->Pos = 0;
    Log2 = new TextLog;
    Log2->Pos = 0;
    
    InitGL();
}

MiniClientCanvas::~MiniClientCanvas()
{

}

//////////////////////////////////////////////////////////////////////
// Method Implementations
//////////////////////////////////////////////////////////////////////
void MiniClientCanvas::InitGL()
{
    SetCurrent(*RCContext);
	glViewport(0, 0, width, height);
    glEnable(GL_TEXTURE_2D);	                // Enable Textures
    
	glShadeModel(GL_SMOOTH);                    // Enables Smooth Color Shading
    glDisable(GL_DEPTH_TEST);                   // Disable Depth Buffer what gets drawn first is on bottom

    glMatrixMode(GL_PROJECTION);                // Set the Matrix mode to Projection
    glLoadIdentity();                           // Clear the Projection matrix

    glEnable(GL_ALPHA_TEST);
    glAlphaFunc(GL_GREATER, 0.0f);
    
    glOrtho(-1, 1, -1, 1, -1, 1);               // Use ortho mode, tibia is 2d

    glMatrixMode(GL_MODELVIEW);                 // Set Matrix Mode to Model View
    glLoadIdentity();                           // Clear the Model View Matrix
}

void MiniClientCanvas::BindTexture(int SpriteId)                             
{   
    if(texture[SpriteId].name == 0)                                                         //if the sprite is not loaded int opengl we must load it
    {
        unsigned char * SpriteArr = app->SpriteReader->GetSprite(SpriteId);                 //Load the sprite
        glGenTextures(1, &texture[SpriteId].name);					                        //Create The Texture
    	glBindTexture(GL_TEXTURE_2D, texture[SpriteId].name);                               //Bind these settings to the texure 
        glTexImage2D(GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, SpriteArr); //Load the sprite into opengl
    	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);                     //Set bilinear filtering for panning
    	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);                     //Set bilinear filtering for zooming
        free(SpriteArr);                                                                    //Free sprite in memory, opengl holds the sprite internally
    } else {                                                                                //Else it is enough just to bind the texture
        glBindTexture(GL_TEXTURE_2D, texture[SpriteId].name);   
    }
    //texture[SpriteId].used = 10;                                                            //Set used to 10, ie it has a life of 10 seconds without being used
    //Log1->SpriteId[Log1->Pos] = SpriteId;                                                   //Add out sprite to the log, so we can count down its life
    //Log1->Pos++;                                                                            //Increment the pos value
}   

void MiniClientCanvas::UpdateTextureLog()
{
    LogDumb = Log1;                                              //Move Log1 to Log2
    Log1 = Log2;
    Log2 = LogDumb; 
    
    Log1->Pos = 0;                                              //We are going to overwrite log1
    int TextureId = 0;                                          //Store textureId so we dont have to keep derefferencing
    int count = Log2->Pos;
    for(int i = 0; i < count; i++)
    {
        TextureId = Log2->SpriteId[i];                          //TextureId is what is stored in Log2
        if(texture[TextureId].used == 0)                        //If the texture has reached the end of its life
        {
            glDeleteTextures(1, &texture[TextureId].name);           //Delete it and free up its memory
        } else {
            texture[TextureId].used--;                          //Else wise decrement its life by 1
            Log1->SpriteId[Log1->Pos] = Log2->SpriteId[i];      //And move the SpriteId from Log2 to Log1
            Log1->Pos++;                                        //Increment pos
        }
    }
}                 

void MiniClientCanvas::Draw(void * pClient)
{
    SetCurrent(*RCContext);
	float xstep = 2/15.0f;
    float ystep = 2/11.0f;
    int texturePos = 0;
    unsigned int objectId;
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(-1.0f - xstep, 1.0f + ystep, 0.0f); //start at top left corner
    Tile * T;
    wxString output;
    int activeframe = 0;
    for(int z = 7; z > -1; z--)
    {
        output.Printf("%i", z);
        wxMessageBox(output);
        for(int y = 0; y < 14; y++)
        {
            for(int x = 0; x < 18; x++)
            {
                float xHeightOffset = 0.0f;
                float yHeightOffset = 0.0f;
                Position p;
                p.x = x;
                p.y = y;
                p.z = z;
                T = ((Client*)pClient)->Map->GetTile(p);
                for(int stackpos = 0; stackpos < T->stackedObjectCount; stackpos++)
                {
                    objectId = T->Things[stackpos].objectId;
                    BindTexture(1);
                    if(objectId < 7900 && objectId >= 100 && objectId != 0x61 && objectId != 0x62)
                    {
                        DatReader::ThingData * thinginfo = &(app->DataReader->ThingInfo[objectId-100]);
                        glTranslatef(-xHeightOffset * xstep, yHeightOffset * ystep, 0.0f);
                        for(int w = 0; w < thinginfo->Width; w++)
                        {
                            for(int h = 0; h < thinginfo->Height; h++)
                            {
                                activeframe = ((thinginfo->Width) * h + w);
                                BindTexture(thinginfo->Sprites[activeframe]-1);
                                glBegin(GL_QUADS);
                            		glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, -ystep, 0.0f);	// Bottom Left Of The Texture and Quad
                            		glTexCoord2f(1.0f, 1.0f); glVertex3f(xstep, -ystep, 0.0f);	// Bottom Right Of The Texture and Quad
                            		glTexCoord2f(1.0f, 0.0f); glVertex3f(xstep, 0.0f, 0.0f);	// Top Right Of The Texture and Quad
                            		glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 0.0f, 0.0f);	// Top Left Of The Texture and Quad
                        	    glEnd();
                	            texturePos++;
                	            glTranslatef(0.0, ystep, 0.0f);
                            }
                            glTranslatef(-xstep, -ystep * thinginfo->Height, 0.0f);
                        }
                        glTranslatef(xstep * thinginfo->Width, 0.0f, 0.0f);
                        glTranslatef(xHeightOffset * xstep, -yHeightOffset * ystep, 0.0f); 
                        xHeightOffset += (float)(((float)thinginfo->HeightChange)/32.0f);
                        yHeightOffset += (float)(((float)thinginfo->HeightChange)/32.0f);
                    }
                }
                glTranslatef(xstep, 0.0f, 0.0f);
            }
            glTranslatef(-xstep * 18, -ystep, 0.0f);
        }
        glTranslatef(0.0f, ystep * 14, 0.0f);
    }
    wxClientDC dc(this);
    Paint(dc);
}

void MiniClientCanvas::Paint(wxDC &dc)
{
//	if(!GetContext())
//		return;

	SetCurrent(*RCContext);
//	float xstep = 2/15.0f;
//    float ystep = 2/11.0f;
//    int texturePos = 0;
//    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//    glLoadIdentity();
//    glTranslatef(-1.0f, 1.0f, 0.0f); //start at top left corner
//    for(int y = 0; y < 2; y++)
//    {
//        for(int x = 0; x < 15; x++)
//        {
//            BindTexture(map[x + y * 15]);
//            glBegin(GL_QUADS);
//        		glTexCoord2f(0.0f, 1.0f); glVertex3f(0, -ystep, 0.0f);	// Bottom Left Of The Texture and Quad
//        		glTexCoord2f(1.0f, 1.0f); glVertex3f(xstep, -ystep, 0.0f);	// Bottom Right Of The Texture and Quad
//        		glTexCoord2f(1.0f, 0.0f); glVertex3f(xstep, 0, 0.0f);	// Top Right Of The Texture and Quad
//        		glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 0.0f, 0.0f);	// Top Left Of The Texture and Quad
//        	glEnd();
//        	glTranslatef(xstep, 0.0f, 0.0f);
//        	texturePos++;
//        }
//        glTranslatef(-2.0f, -ystep, 0.0f);
//    }
	// Swap Your Buffers
	SwapBuffers();

}


//////////////////////////////////////////////////////////////////////
// Event Handler Implementations
//////////////////////////////////////////////////////////////////////

void MiniClientCanvas::OnPaint(wxPaintEvent& event)
{
	wxPaintDC dc(this);
	Paint(dc);
	event.Skip();
}

void MiniClientCanvas::OnDraw(wxGUIEvent& event)
{
    wxMessageBox("test");
	Draw((void*)event.GetParam1());
	event.Skip();
}

void MiniClientCanvas::OnEraseBackground(wxEraseEvent& event)
{
	// Do Nothing to Avoid Flashing on MSW
}

void MiniClientCanvas::OnIdle(wxIdleEvent& event)
{
	//this->Refresh();  // invoking this chews up lots of cpu cycles, not needed for static pictures, onpaint is sufficient
}


